﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Synchronization.Files;
using Microsoft.Synchronization;
using System.IO;
using System.Windows;

namespace EnterpriseDataBackuper.Core
{
    /// <summary>
    /// Performs sync between two given paths for file recovery or creating backup
    /// </summary>
    public class SyncEngine
    {
        private FileSyncProvider sourceProvider;

        public FileSyncProvider SourceProvider
        {
            get { return sourceProvider; }
        }
        private FileSyncProvider destinationProvider;



        public string configureSourceProvider(string sourcePath, string guid)
        {
            Guid replicaID;
            if (null == guid || guid == "" || true)
                replicaID = Guid.NewGuid();
            else
                replicaID = new Guid(guid);
         
            if (!new DirectoryInfo(sourcePath).Exists)
            {
                DirectoryInfo d = new DirectoryInfo(sourcePath);
                d.Create();
            }
            else
            {
                DirectoryInfo d = new DirectoryInfo(sourcePath);
                d.Parent.Create();
            }      
           
            sourceProvider = new FileSyncProvider(replicaID, sourcePath);
            return replicaID.ToString();
        }

        public string configureDestinationProvider(string sourcePath, string destinationPath, string guid)
        {
            Guid replicaID;
            if (null == guid || guid == "" || true)
                replicaID = Guid.NewGuid();
            else
                replicaID = new Guid(guid);
            
            //odtworz strukture na penie
            if (new DirectoryInfo(sourcePath).Exists)
            {
                DirectoryInfo d = new DirectoryInfo(destinationPath);
                d.Create();
            }
            else
            {
                DirectoryInfo d = new DirectoryInfo(destinationPath);
                d.Parent.Create();
            }           

            destinationProvider = new FileSyncProvider(replicaID, destinationPath);
            return replicaID.ToString();
        }

        public SyncEngine()
        {
        }

        private List<string> GetFilesAndDirectories(String directory)
        {
            List<String> result = new List<String>();
            Stack<String> stack = new Stack<String>();
            stack.Push(directory);

            while (stack.Count > 0)
            {
                String temp = stack.Pop();

                try
                {
                    result.AddRange(Directory.GetFiles(temp, "*.*"));

                    foreach (string directoryName in
                      Directory.GetDirectories(temp))
                    {
                        stack.Push(directoryName);
                    }
                }
                catch
                {
                    throw new Exception("Error retrieving file or directory.");
                }
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        public void CreateBackup() //FileSyncScopeFilter filter, FileSyncOptions options
        {
            //set options
            /*
            SyncAgent syncAgent = new SyncAgent();
            syncAgent.LocalProvider = sourceProvider;
            syncAgent.RemoteProvider = destinationProvider;
            syncAgent.Synchronize();
            */
            SyncOperationStatistics syncOperationStatistics;
            SyncOrchestrator synchronizationAgent = new SyncOrchestrator();
            synchronizationAgent.Direction = SyncDirectionOrder.Upload;
            synchronizationAgent.LocalProvider = sourceProvider;
            synchronizationAgent.RemoteProvider = destinationProvider;
            try
            {
                //Start the synchronization process
                syncOperationStatistics = synchronizationAgent.Synchronize();
                //Assign synchronization statistics to the lstStatistics control
            }
            catch (Microsoft.Synchronization.SyncException se)
            {
                MessageBox.Show(se.Message, "Sync Files - Error");
                return;
            }
            finally
            {
                // Release resources once done
                if (sourceProvider != null)
                    sourceProvider.Dispose();
                if (destinationProvider != null)
                    destinationProvider.Dispose();
            }
        }

        public void Restore() //FileSyncScopeFilter filter, FileSyncOptions options
        {
            //set options
            /*
            SyncAgent syncAgent = new SyncAgent();
            syncAgent.LocalProvider = sourceProvider;
            syncAgent.RemoteProvider = destinationProvider;
            syncAgent.Synchronize();
            */
            SyncOperationStatistics syncOperationStatistics;
            SyncOrchestrator synchronizationAgent = new SyncOrchestrator();
            synchronizationAgent.Direction = SyncDirectionOrder.Download;
            synchronizationAgent.LocalProvider = sourceProvider;
            synchronizationAgent.RemoteProvider = destinationProvider;
            try
            {
                //Start the synchronization process
                syncOperationStatistics = synchronizationAgent.Synchronize();
                Console.WriteLine("RESTORE: Applied: {0}, Failed: {1}", syncOperationStatistics.DownloadChangesApplied, syncOperationStatistics.DownloadChangesFailed);
                //Assign synchronization statistics to the lstStatistics control
            }
            catch (Microsoft.Synchronization.SyncException se)
            {
                MessageBox.Show(se.Message, "Sync Files - Error");
                return;
            }
            finally
            {
                // Release resources once done
                if (sourceProvider != null)
                    sourceProvider.Dispose();
                if (destinationProvider != null)
                    destinationProvider.Dispose();
            }
        }

        private Guid GetReplicaID(string guidPath)
        {
            if (!File.Exists(guidPath)) //Create a new GUID and store it in a file
            {
                Guid replicaID = Guid.NewGuid();
                using (FileStream fileStream = File.Open(guidPath, FileMode.Create))
                {
                    using (StreamWriter streamWriter = new StreamWriter(fileStream))
                    {
                        streamWriter.WriteLine(replicaID.ToString());
                    }
                }
                return replicaID;
            }
            else //Read and return the GUID from the file
            {
                using (FileStream fileStream = File.Open(guidPath, FileMode.Open))
                {
                    using (StreamReader streamReader = new StreamReader(fileStream))
                    {
                        return new Guid(streamReader.ReadLine());
                    }
                }
            }
        }
    }
}
